package com.doudizu.shoesonline.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.doudizu.shoesonline.common.ErrorCode;
import com.doudizu.shoesonline.common.UserContext;
import com.doudizu.shoesonline.constant.CodeConstant;
import com.doudizu.shoesonline.exception.BusinessException;
import com.doudizu.shoesonline.mapper.UserMapper;
import com.doudizu.shoesonline.model.dto.user.UserDTO;
import com.doudizu.shoesonline.model.dto.user.UserQuery;
import com.doudizu.shoesonline.model.entity.Link;
import com.doudizu.shoesonline.model.entity.User;
import com.doudizu.shoesonline.model.vo.UserVO;
import com.doudizu.shoesonline.service.LinkService;
import com.doudizu.shoesonline.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import javax.annotation.Resource;
import javax.mail.internet.MimeMessage;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import static com.doudizu.shoesonline.constant.UserConstant.USER_LOGIN;

/**
 * @description 针对表【user(用户)】的数据库操作Service实现
 * @createDate 2023-07-03 09:55:55
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
        implements UserService {

    @Resource
    private LinkService linkService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Resource
    private JavaMailSender javaMailSender;

    @Value("${spring.mail.username:}")
    private String sendUserName;

    /**
     * 注册
     *
     * @param
     * @return
     */
    @Override
    public void userRegister(UserDTO user) {
        String userAccount = user.getAccount();
        String userPassword = user.getPassword();
        // 1. 校验
        if (StringUtils.isAnyBlank(userAccount, userPassword)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");
        }
        if (userAccount.length() < 4) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户账号应大于四位");
        }
        if (userPassword.length() < 6) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户密码应大于6位");
        }
        // TODO 验证码
        String code = redisTemplate.opsForValue().get(CodeConstant.CHECK_CODE_KEY_EMAIL + ":" + user.getEmail());
        if (StringUtils.isBlank(code)) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "验证码未发送");
        }
        if (user.getCode() == null || !code.equals(user.getCode())) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "验证码错误");
        }
        //TODO 邮箱 电话等信息校验
        synchronized (userAccount.intern()) {
            // 账户不能重复
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("account", userAccount);
            long count = this.baseMapper.selectCount(queryWrapper);
            if (count > 0) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号重复");
            }
            // 2. 加密
            userPassword = DigestUtils.md5DigestAsHex(("shoes_online" + userPassword).getBytes());
            user.setPassword(userPassword);
            User user1 = new User();
            BeanUtil.copyProperties(user, user1);
            // 3. 插入数据
            boolean saveResult = this.save(user1);
            if (!saveResult) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "注册失败，数据库错误");
            }
        }
    }


    @Override
    public boolean updateUser(UserDTO user) {
        User user1 = new User();
        BeanUtil.copyProperties(user, user1);
        if (user.getId() != null) {
            user1.setId(user.getId());
        }
        if (user.getStatus() != null) {
            user1.setStatus(user.getStatus());
        }
        if (user.getId() == null) {
            user1.setId(getLoginUser().getId());
        }
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("account", user.getAccount());
        long count = this.baseMapper.selectCount(queryWrapper);
        if (count > 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号重复");
        }
        if (user.getPicIds() == null || user.getPicIds().isEmpty()) {
            return this.updateById(user1);
        }

        Link link = new Link();
        link.setId(user.getPicIds().get(0));
        if (user.getUsername() != null) {
            link.setLinkName(user.getUsername() + "的头像");
        }
        if (user.getUsername() == null) {
            User byId = this.getById(user1.getId());
            link.setLinkName(byId.getUsername() + "的头像");
        }
        linkService.updateById(link);
        user1.setPictureLinkId(link.getId());
        return this.updateById(user1);
    }

    @Override
    public String userLogin(String userAccount, String userPassword) {
        // 1. 校验
        if (StringUtils.isAnyBlank(userAccount, userPassword)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");
        }
        if (userAccount.length() < 4) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号错误");
        }
        if (userPassword.length() < 6) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码错误");
        }
        // 2. 加密
        String encryptPassword = DigestUtils.md5DigestAsHex(("shoes_online" + userPassword).getBytes());
        // 查询用户是否存在
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("account", userAccount);
        queryWrapper.eq("password", encryptPassword);
        User user = this.baseMapper.selectOne(queryWrapper);
        // 用户不存在
        if (user == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户不存在或密码错误");
        }
        // 账号被禁用
        if (user.getStatus() == 0) {
            throw new BusinessException(ErrorCode.FORBIDDEN_ERROR, "账号状态异常");
        }
        // 3. 记录用户的登录态
        String token = UUID.randomUUID().toString();
        // 14天过期时间
        redisTemplate.opsForValue().set(USER_LOGIN + token, String.valueOf(user.getId()), 14, TimeUnit.DAYS);
        return token;
    }

    @Override
    public boolean userLogout(String token) {
        String userId = redisTemplate.opsForValue().get(USER_LOGIN + token);
        if (userId == null) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "未登录");
        }
        // 移除登录态
        redisTemplate.delete(USER_LOGIN + token);
        return true;
    }

    @Override
    public IPage<User> getUsers(UserQuery userQuery) {
        Integer pageNum = userQuery.getPageNum();
        Integer pageSize = userQuery.getPageSize();
        //TODO 可选分页
        if (pageNum == null || pageSize == null) {
            pageNum = 1;
            pageSize = 5;
        }
        Page<User> objectPage = new Page<>(pageNum, pageSize);
        QueryWrapper<User> brandQueryWrapper = new QueryWrapper<>();
        if (userQuery != null && userQuery.getStatus() != null) {
            brandQueryWrapper.eq("status", userQuery.getStatus());
        }
        brandQueryWrapper.like(userQuery.getUsername() != null, "username", userQuery.getUsername());
        Page<User> page = this.page(objectPage, brandQueryWrapper);
        return page;
    }

    @Override
    public List<User> searchUsers(String gender, String userName) {
        //        都为空的时候返回参数错误
        if (StringUtils.isBlank(gender) && StringUtils.isBlank(userName)) {
            IPage<User> users = this.getUsers(null);
            return users.getRecords();
        }
//        拼接模糊查询sql
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.like(gender != null, User::getGender, "男".equals(gender) ? 0 : 1)
                .like(StringUtils.isNotBlank(userName), User::getUsername, userName);
        List<User> userList = this.list(lambdaQueryWrapper);
        return userList;

    }

    @Override
    public UserVO getUser(Integer userId) {
        User user = this.getById(userId);
        Integer pictureLinkId = user.getPictureLinkId();
        String url = linkService.getById(pictureLinkId).getUrl();
        UserVO userVO = new UserVO();
        userVO.setPictureLink(url);
        BeanUtil.copyProperties(user, userVO);
        return userVO;
    }


    @Override
    public boolean reset(String password, String account, String answer) {
        if (account == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "请输入正确的账号");
        }
        if (account.length() < 4) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户账号应大于四位");
        }
        if (password.length() < 6) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户密码应大于6位");
        }
        LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userLambdaQueryWrapper.eq(User::getAccount, account);
        User user = this.getOne(userLambdaQueryWrapper);
        if (user == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户不存在");
        }
        if (!user.getAnswer().equals(answer)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "答案错误");
        }
        user.setPassword(DigestUtils.md5DigestAsHex(("shoes_online" + password).getBytes()));
        return this.updateById(user);
    }

    @Override
    public void sendEmailCode(String toEmail) {
        String code = RandomStringUtils.random(5, false, true);
        redisTemplate.delete(CodeConstant.CHECK_CODE_KEY_EMAIL + ":" + toEmail);
        try {
            MimeMessage message = javaMailSender.createMimeMessage();

            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            //邮件发件人
            helper.setFrom(sendUserName);
            //邮件收件人 1或多个
            helper.setTo(toEmail);
            //邮件主题
            helper.setSubject("邮箱验证码");
            //邮件内容
            helper.setText(String.format("【鞋城-Online】您好，您的邮箱验证码是：%s，15分钟有效，请勿告知其他人！！", code));
            //邮件发送时间
            helper.setSentDate(new Date());
            //发送
            javaMailSender.send(message);
            redisTemplate.opsForValue().set(CodeConstant.CHECK_CODE_KEY_EMAIL + ":" + toEmail, code, 15, TimeUnit.MINUTES);
        } catch (Exception e) {
            log.error("邮件发送失败", e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "邮件发送失败");
        }
    }

    @Override
    public void addUser(UserDTO user) {
        String userAccount = user.getAccount();
        String userPassword = user.getPassword();
        // 1. 校验
        if (StringUtils.isAnyBlank(userAccount, userPassword)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");
        }
        if (userAccount.length() < 4) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户账号应大于四位");
        }
        if (userPassword.length() < 6) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户密码应大于6位");
        }
        //TODO 邮箱 电话等信息校验
        synchronized (userAccount.intern()) {
            // 账户不能重复
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("account", userAccount);
            long count = this.baseMapper.selectCount(queryWrapper);
            if (count > 0) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号重复");
            }
            // 2. 加密
            userPassword = DigestUtils.md5DigestAsHex(("shoes_online" + userPassword).getBytes());
            user.setPassword(userPassword);
            User user1 = new User();
            BeanUtil.copyProperties(user, user1);
            // 3. 插入数据
            boolean saveResult = this.save(user1);
            if (!saveResult) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "注册失败，数据库错误");
            }
        }
    }


    public UserVO getLoginUserVO(User user) {
        if (user == null) {
            return null;
        }
        UserVO loginUserVO = new UserVO();
        BeanUtils.copyProperties(user, loginUserVO);
        loginUserVO.setPictureLink(linkService.getById(user.getPictureLinkId()).getUrl());
        return loginUserVO;
    }

    @Override
    public User getLoginUser() {
        // 先判断是否已登录
        Long userId = UserContext.getUserId();
        if (userId == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
        }
        // 从数据库查询（追求性能的话可以注释，直接走缓存）
        User currentUser = this.getById(userId);
        if (currentUser == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
        }
        return currentUser;
    }

}




